// compile: g++ -o shape_wrapper1 shape_wrapper1.cc -std=c++11
// run: ./shape_wrapper1
#include <iostream>
using namespace std;
// auto_ptr的实现，强调对象的所有权
// 问题：如果把它传递给另外一个 SmartPtr，你就不再拥有这个对象了
template <typename T>
class SmartPtr1 {
 public:
  explicit SmartPtr1(T* ptr = nullptr) : ptr_(ptr) {}
  ~SmartPtr1() { delete ptr_; }
  T* get() const { return ptr_; }

  T& operator*() const { return *ptr_; }
  T* operator->() const { return ptr_; }
  operator bool() { return ptr_; }

  SmartPtr1(SmartPtr1& other) { ptr_ = other.release(); }
  SmartPtr1& operator=(SmartPtr1& rhs) {
    SmartPtr1(rhs).swap(*this);
    return *this;
  }
  T* release() {
    T* ptr = ptr_;
    ptr_ = nullptr;
    return ptr;
  }
  void swap(SmartPtr1& rhs) {
    using std::swap;
    swap(ptr_, rhs.ptr_);
  }

 private:
  T* ptr_;
};
void Test1() {
  SmartPtr1<int> sp1(new int(10));
  SmartPtr1<int> sp2 = sp1;
  int* tmp = sp1.get();  // tmp值为nullptr
  cout << *sp2.get() << endl;
  // cout << *tmp << endl; 段错误
}
// 在auto_ptr的基础上引入移动语义
// unique_ptr的实现原理
// 使用场景有限
template <typename T>
class SmartPtr2 {
 public:
  explicit SmartPtr2(T* ptr = nullptr) : ptr_(ptr) {}
  ~SmartPtr2() { delete ptr_; }
  T* get() const { return ptr_; }

  T& operator*() const { return *ptr_; }
  T* operator->() const { return ptr_; }
  operator bool() { return ptr_; }

  // 如果提供了移动构造函数而没有手动提供拷贝构造函数，那后者自动被禁用
  SmartPtr2(SmartPtr2&& other) { ptr_ = other.release(); }
  SmartPtr2& operator=(SmartPtr2 rhs) {
    rhs.swap(*this);
    return *this;
  }
  T* release() {
    T* ptr = ptr_;
    ptr_ = nullptr;
    return ptr;
  }

 private:
  T* ptr_;
};
void Test2() {
  SmartPtr2<int> sp1(new int(10));
  cout << *sp1.get() << endl;
  // SmartPtr2<int> sp2 = sp1;  // 错误，unique_ptr禁止拷贝构造
  SmartPtr2<int> sp2 = std::move(sp1);
  cout << *sp2.get() << endl;
  // 错误，sp1已经被move了，即承诺不再使用sp1,以保证安全
  // cout << *sp1.get() << endl;
}

class shared_count {
 public:
  shared_count() : count_(1) {}
  void add_count() { ++count_; }
  // 返回long的原因是看一看引用计数是否减到0了
  long reduce_count() { return --count_; }
  long get_count() const { return count_; }

 private:
  long count_;
};
int main() {
  // Test1();
  Test2();
  Test3();
  return 0;
}